using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.IO;

namespace TrafficTrouble.Core
{
    public static class History
    {
        private static Stack<HistoryItem> history;

        public static bool HasHistory { get { return history.Count > 0; } }
        public static int Length { get { return history.Count; } }
        public static HistoryItem GetLastMove()
        {
            if (history.Count > 0) return history.Pop();
            else throw new NoHistoryException("TrafficTrouble.Core.History.GetLastMove()");
        }

        public static void AddMove(HistoryItem move)
        {
            history.Push(move);
        }

        public static void Reset()
        {
            history = new Stack<HistoryItem>();
        }

        public static void WriteToStream(StreamWriter writer, byte formatVersion)
        {
            if (formatVersion == 1)
            {
                writer.Write(History.Length);
                foreach (HistoryItem item in history)
                {
                    writer.WriteLine();
                    writer.Write((int)item.Car.ID + " " 
                        + item.Start.X + " " + item.Start.Y + " "
                        + item.End.X + " " + item.End.Y);
                }
            }
            else throw new Exception("Unknown level format version number '" + formatVersion
               + ". (TrafficTrouble.Core.History.WriteToStream(StreamWriter, byte)).");
        }
        public static void ReadFromStream(StreamReader reader, byte formatVersion, Grid level)
        {
            History.Reset();
            if (formatVersion == 1)
            {
                int historyLength = int.Parse(reader.ReadLine());
                // lol I'm using the 'approaches' operator (-->).
                // read it as 'as historyLength approaches 0.'
                while (historyLength --> 0)
                {
                    string[] moveInfo = reader.ReadLine().Split(' ');
                    byte carID = byte.Parse(moveInfo[0]);
                    int startX = int.Parse(moveInfo[1]);
                    int startY = int.Parse(moveInfo[2]);
                    int endX = int.Parse(moveInfo[3]);
                    int endY = int.Parse(moveInfo[4]);

                    Car car = null;
                    foreach (Car c in level.Cars)
                        if (c.ID == carID)
                            car = c;
                    if (car == null)
                        throw new Exception("Could not find car with ID of " + carID
                            + ". (TrafficTrouble.Core.History.ReadFromStream(StreamReader, byte, Grid)).");

                    history.Push(new HistoryItem(car, new Point(startX, startY), new Point(endX, endY)));
                }

                history = new Stack<HistoryItem>(history.Reverse());
            }
            else throw new Exception("Unknown level format version number '" + formatVersion
               + ". (TrafficTrouble.Core.History.ReadFromStream(StreamReader, byte, Grid)).");
        }
    }

    public struct HistoryItem
    {
        private Car _car;
        public Car Car { get { return this._car; } set { this._car = value; } }

        private Point _start, _end;
        public Point Start { get { return this._start; } set { this._start = value; } }
        public Point End { get { return this._end; } set { this._end = value; } }

        public HistoryItem(Car car, Point start, Point end)
        {
            this._car = car;
            this._start = start;
            this._end = end;
        }

        public override string ToString()
        {
            return base.ToString();
        }
    }

    public class NoHistoryException : Exception
    {
        public NoHistoryException(string source) : base("The player has made no previous moves. (" + source + ").") { }
    }
}
